﻿//
// --------------------------------------------------------------------------
//  Gurux Ltd
//
//
//
// Filename:        $HeadURL$
//
// Version:         $Revision$,
//                  $Date$
//                  $Author$
//
// Copyright (c) Gurux Ltd
//
//---------------------------------------------------------------------------
//
//  DESCRIPTION
//
// This file is a part of Gurux Device Framework.
//
// Gurux Device Framework is Open Source software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; version 2 of the License.
// Gurux Device Framework is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// This code is licensed under the GNU General Public License v2.
// Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
//---------------------------------------------------------------------------
using Gurux.Common.Db;
using Gurux.DLMS.AMI.Shared.DTOs.Authentication;
using Gurux.DLMS.AMI.Shared.DTOs.Enums;
using Gurux.DLMS.AMI.Shared.DTOs.Module;
using Gurux.DLMS.AMI.Shared.DTOs.Workflow;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;

namespace Gurux.DLMS.AMI.Shared.DTOs.Script
{
    /// <summary>
    /// Gurux AMI script.
    /// </summary>
    public class GXScript : GXTableBase, IUnique<Guid>
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public GXScript()
        {
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <remarks>
        /// This constuctor is called when a new script is created. It will create all needed lists.
        /// </remarks>
        /// <param name="name">Script name.</param>
        public GXScript(string? name)
        {
            Name = name;
            ServerSide = true;
            ScriptGroups = new List<GXScriptGroup>();
            Workflows = new List<GXWorkflow>();
            Methods = new List<GXScriptMethod>();
            Logs = new List<GXScriptLog>();
            TraceLevel = System.Diagnostics.TraceLevel.Error;
        }

        /// <summary>
        /// Script identifier.
        /// </summary>
        [DataMember(Name = "ID")]
        [DefaultValue(null)]
        [Filter(FilterType.Exact)]
        public Guid Id
        {
            get;
            set;
        }

        /// <summary>
        /// Is script active.
        /// </summary>
        [DefaultValue(true)]
        [Filter(FilterType.Exact)]
        [IsRequired]
        public bool? Active { get; set; }


        /// <summary>
        /// Script name.
        /// </summary>
        [StringLength(64)]
        [Filter(FilterType.Contains)]
        public string? Name
        {
            get;
            set;
        }

        /// <summary>
        /// Script description.
        /// </summary>
        [DataMember]
        [Filter(FilterType.Contains)]
        [StringLength(256)]
        //Filter uses default value.
        [DefaultValue(null)]
        public string? Description
        {
            get;
            set;
        }

        /// <summary>
        /// Script language.
        /// </summary>
        public ScriptLanguage Language
        {
            get;
            set;
        }

        /// <summary>
        /// Source code of the script.
        /// </summary>
        [DataMember]
        public string? SourceCode
        {
            get;
            set;
        }
        /// <summary>
        /// Comma separated list from additional namespaces.
        /// </summary>
        [DataMember]
        public string? Namespaces
        {
            get;
            set;
        }

        /// <summary>
        /// Is script run on server or in the client end.
        /// </summary>
        /// <remarks>
        /// Usually the script is run on the server side, but sometimes there are cases that doesn't 
        /// need the server resources and it's possible to run the script on the client side. 
        /// </remarks>
        public bool ServerSide { get; set; } = true;

        /// <summary>
        /// Generated byte assembly.
        /// </summary>
        [DataMember]
        public byte[]? ByteAssembly
        {
            get;
            set;
        }

        /// <summary>
        /// The creator of the script.
        /// </summary>
        [DataMember]
        [ForeignKey(OnDelete = ForeignKeyDelete.None)]
        [Filter(FilterType.Exact)]
        [IsRequired]
        public GXUser? Creator
        {
            get;
            set;
        }

        /// <summary>
        /// The module that created this script.
        /// </summary>
        [DataMember]
        [ForeignKey(OnDelete = ForeignKeyDelete.None)]
        [Filter(FilterType.Exact)]
        public GXModule? Module
        {
            get;
            set;
        }

        /// <summary>
        /// List of script method that this script can offer.
        /// </summary>
        [DataMember]
        [Filter(FilterType.Contains)]
        public List<GXScriptMethod>? Methods
        {
            get;
            set;
        }

        /// <summary>
        /// List of script groups where this script belongs.
        /// </summary>
        [DataMember]
        [ForeignKey(typeof(GXScriptGroup), typeof(GXScriptGroupScript))]
        [Filter(FilterType.Contains)]
        public List<GXScriptGroup>? ScriptGroups
        {
            get;
            set;
        }

        /// <summary>
        /// List of workflows where this script belongs.
        /// </summary>
        [DataMember]
        [ForeignKey(typeof(GXWorkflow), typeof(GXWorkflowScriptMethod))]
        [Filter(FilterType.Contains)]
        public List<GXWorkflow>? Workflows
        {
            get;
            set;
        }

        /// <summary>
        /// Script logs.
        /// </summary>
        [DataMember, ForeignKey(typeof(GXScriptLog))]
        [Filter(FilterType.Contains)]
        public List<GXScriptLog>? Logs
        {
            get;
            set;
        }


        /// <summary>
        /// Localized strings for this script.
        /// </summary>
        /// <remarks>
        /// This is used only for database and it's not send for the user.
        /// </remarks>
        [DataMember]
        [JsonIgnore]
        public GXLocalizedResource[]? Resources
        {
            get;
            set;
        }

        /// <summary>
        /// Localized resources for this script.
        /// </summary>
        /// <remarks>
        /// Localized resources are return with this.
        /// </remarks>
        [DataMember]
        [Ignore(IgnoreType.Db)]
        public GXLanguage[]? Languages
        {
            get;
            set;
        }

        /// <summary>
        /// Creation time.
        /// </summary>
        [DataMember]
        [DefaultValue(null)]
        [Index(false, Descend = true)]
        [Filter(FilterType.GreaterOrEqual)]
        [IsRequired]
        public DateTime? CreationTime
        {
            get;
            set;
        }

        /// <summary>
        /// When the Script is updated for the last time.
        /// </summary>
        [DataMember]
        [Filter(FilterType.GreaterOrEqual)]
        public DateTimeOffset? Updated
        {
            get;
            set;
        }

        /// <summary>
        /// Remove time.
        /// </summary>
        [DataMember]
        [Index(false, Descend = true)]
        [DefaultValue(null)]
        [Filter(FilterType.Null)]
        public DateTimeOffset? Removed
        {
            get;
            set;
        }

        /// <summary>
        /// User has modified the item.
        /// </summary>
        [IgnoreDataMember]
        [Ignore]
        [JsonIgnore]
        public bool Modified
        {
            get;
            set;
        }

        /// <summary>
        /// Used trace level.
        /// </summary>
        [DataMember]
        [DefaultValue(System.Diagnostics.TraceLevel.Error)]
        [Description("Used trace level.")]
        [IsRequired]
        public TraceLevel? TraceLevel
        {
            get;
            set;
        }

        /// <summary>
        /// Concurrency stamp.
        /// </summary>
        /// <remarks>
        /// Concurrency stamp is used to verify that several user's can't 
        /// modify the target at the same time.
        /// </remarks>
        [DataMember]
        [StringLength(36)]
        public string? ConcurrencyStamp
        {
            get;
            set;
        }

        /// <summary>
        /// Update creation time before update.
        /// </summary>
        public override void BeforeAdd()
        {
            if (CreationTime == DateTime.MinValue)
            {
                CreationTime = DateTime.Now;
            }
        }

        /// <summary>
        /// Update concurrency stamp.
        /// </summary>
        public override void BeforeUpdate()
        {
            Updated = DateTime.Now;
        }

        /// <inheritdoc/>
        public override string ToString()
        {
            if (!string.IsNullOrEmpty(Name))
            {
                return Name;
            }
            return nameof(GXScript);
        }
    }
}
